/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ru.ssau.entities;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import javax.sql.DataSource;
import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
import javax.ejb.NoSuchEntityException;
import javax.ejb.ObjectNotFoundException;
import javax.ejb.RemoveException;
import javax.naming.NamingException;
import org.jdom.Element;
import ru.ssau.lib.StringIntegerPair;
import ru.ssau.utils.XMLHelper;
import ru.ssau.utils.DatabaseUtil;


public class MessageBean implements EntityBean {

    private static final String REQUEST_MESSAGE_ADD =
            "INSERT INTO Messages(MessageId,MsgCaption,MsgText,"
            + "UserId,ThreadId,PostTime) VALUES(?,?,?,?,?,?)";
    private static final String REQUEST_MESSAGE_ID_SEQUENCE_GET_NEXT_VALUE =
            "SELECT MessageIDSeq.NEXTVAL FROM dual";
    private static final String REQUEST_MESSAGE_UPDATE =
            "UPDATE Messages SET MsgCaption=?,MsgText=?,"
            + "UserId=?,ThreadId=?,PostTime=? WHERE MessageId=?";
    private static final String REQUEST_MESSAGE_DELETE_BY_ID =
            "DELETE FROM Messages WHERE MessageId=?";
    private static final String REQUEST_MESSAGE_GET_BY_ID =
            "SELECT MsgCaption,MsgText,UserId,ThreadId,PostTime "
            + "FROM Messages WHERE MessageId=?";
    private static final String REQUEST_MESSAGE_FIND_BY_ID =
            "SELECT MessageId FROM Messages WHERE MessageId=?";
    private static final String REQUEST_MESSAGE_GET_ALL =
            "SELECT MessageId,MsgCaption,MsgText,UserId,ThreadId,PostTime "
            + "FROM Messages";
    private static final String REQUEST_MESSAGE_FIND_BY_CAPTION =
            "SELECT MessageId FROM Messages WHERE UPPER(MsgCaption) LIKE UPPER(?)";
    private static final String REQUEST_MESSAGES_GET_ALL_AS_STRING_INTEGER_PAIRS =
            "SELECT MessageId, MsgCaption FROM Messages";

    private Integer id;
    private String caption;
    private String text;
    private Integer userId;
    private Integer threadId;
    private Date postDate;

    private EntityContext entityContext;
    private DataSource dataSource;

    private boolean isEdited;

    public void setEntityContext(EntityContext ctx) {
        try {
            entityContext = ctx;
            dataSource = DatabaseUtil.getDataSource();
            isEdited = false;
        } catch (NamingException ex) {
            throw new EJBException("Cannon lookup connection pool on server", ex);
        }
    }

    public void unsetEntityContext() {
        entityContext = null;
    }

    public Integer ejbCreate(String caption, String text, Integer userId, Integer threadId, Date postDate) throws CreateException {
        PreparedStatement idGeneratePS = null;
        PreparedStatement updatePS = null;
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            //id generation
            idGeneratePS = conn.prepareStatement(REQUEST_MESSAGE_ID_SEQUENCE_GET_NEXT_VALUE);
            ResultSet rs = idGeneratePS.executeQuery();
            if(rs.next()) {
                id = rs.getInt(1);
            } else {
                throw new CreateException("Cannot generate id for message");
            }
            //database updating
            updatePS = conn.prepareStatement(REQUEST_MESSAGE_ADD);
            updatePS.setInt(1, id.intValue());
            updatePS.setString(2, caption);
            updatePS.setString(3, text);
            updatePS.setInt(4, userId.intValue());
            updatePS.setInt(5, threadId.intValue());
            Timestamp postTime = new Timestamp(postDate.getTime());
            updatePS.setTimestamp(6, postTime);
            if(updatePS.executeUpdate() != 1) {
                throw new CreateException("Insertion error");
            }
            this.caption = caption;
            this.text = text;
            this.userId = userId;
            this.threadId = threadId;
            this.postDate = postDate;
            isEdited = false;
            return id;
        } catch(SQLException ex) {
            throw new EJBException("Error in INSERT statement", ex);
        } finally {
            DatabaseUtil.closeConnection(conn, idGeneratePS);
            DatabaseUtil.closeConnection(null, updatePS);
        }
    }

    public void ejbPostCreate(String caption, String text, Integer userId, Integer threadId, Date postDate) throws CreateException {

    }

    public Integer ejbFindByPrimaryKey(Integer primaryKey) throws ObjectNotFoundException {
        PreparedStatement ps = null;
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            ps = conn.prepareStatement(REQUEST_MESSAGE_FIND_BY_ID);
            ps.setInt(1, primaryKey.intValue());
            ResultSet rs = ps.executeQuery();
            if(!rs.next()) {
                throw new ObjectNotFoundException("No entity found by id = " + primaryKey.toString());
            }
            return primaryKey;
        } catch(SQLException ex) {
            throw new EJBException("Error in SELECT statement", ex);
        } finally {
            DatabaseUtil.closeConnection(conn, ps);
        }
    }

    public Collection<Integer> ejbFindByCaption(String caption) {
        PreparedStatement ps = null;
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            LinkedList<Integer> keys = new LinkedList<Integer>();
            ps = conn.prepareStatement(REQUEST_MESSAGE_FIND_BY_CAPTION);
            ps.setString(1, DatabaseUtil.getContainsPattern(caption));
            ResultSet rs = ps.executeQuery();
            while(rs.next()) {
                Integer key = Integer.valueOf(rs.getInt(1));
                keys.add(key);
            }
            return keys;
        } catch(SQLException ex) {
            throw new EJBException("Error in SELECT statement", ex);
        } finally {
            DatabaseUtil.closeConnection(conn, ps);
        }
    }

    public void ejbActivate() {

    }

    public void ejbPassivate() {

    }

    public void ejbLoad() {
        PreparedStatement ps = null;
        Connection conn = null;
        id = (Integer) entityContext.getPrimaryKey();
        try {
            conn = dataSource.getConnection();
            ps = conn.prepareStatement(REQUEST_MESSAGE_GET_BY_ID);
            ps.setInt(1, id);
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                caption = rs.getString("MsgCaption");
                text = rs.getString("MsgText");
                userId = Integer.valueOf(rs.getInt("UserId"));
                threadId = Integer.valueOf(rs.getInt("ThreadId"));
                postDate = new Date(rs.getTimestamp("PostTime").getTime());
            } else {
                throw new NoSuchEntityException("No entity found by id = " + id.toString());
            }
            isEdited = false;
        } catch (SQLException ex) {
            throw new EJBException("Error in SELECT statement", ex);
        } finally {
            DatabaseUtil.closeConnection(conn, ps);
        }
    }

    public void ejbStore() {
        if(!isEdited) return;
        PreparedStatement ps = null;
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            ps = conn.prepareStatement(REQUEST_MESSAGE_UPDATE);
            ps.setString(1, caption);
            ps.setString(2, text);
            ps.setInt(3, userId.intValue());
            ps.setInt(4, threadId.intValue());
            Timestamp postTime = new Timestamp(postDate.getTime());
            ps.setTimestamp(5, postTime);
            ps.setInt(6, id.intValue());
            if(ps.executeUpdate() < 1) {
                throw new NoSuchEntityException("No entity found by id = " + id.toString());
            }
            isEdited = false;
        } catch(SQLException ex) {
            throw new EJBException("Error in UPDATE statement", ex);
        } finally {
            DatabaseUtil.closeConnection(conn, ps);
        }
    }

    public void ejbRemove() throws RemoveException {
        PreparedStatement ps = null;
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            ps = conn.prepareStatement(REQUEST_MESSAGE_DELETE_BY_ID);
            ps.setInt(1, id.intValue());
            if(ps.executeUpdate() < 1) {
                throw new NoSuchEntityException("No entity found by id = " + id.toString());
            }
            isEdited = false;
        } catch(SQLException ex) {
            throw new EJBException("Error in DELETE statement", ex);
        } finally {
            DatabaseUtil.closeConnection(conn, ps);
        }
    }

    public Collection<StringIntegerPair> ejbHomeGetAllAsStringIntegerPairs() {
        PreparedStatement ps = null;
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            ps = conn.prepareStatement(REQUEST_MESSAGES_GET_ALL_AS_STRING_INTEGER_PAIRS);
            ResultSet rs = ps.executeQuery();
            Collection<StringIntegerPair> pairs = new LinkedList<StringIntegerPair>();
            while(rs.next()) {
                Integer messageId = Integer.valueOf(rs.getInt("MessageId"));
                String messageCaption = rs.getString("MsgCaption");
                StringIntegerPair pair = new StringIntegerPair(messageId, messageCaption);
                pairs.add(pair);
            }
            return pairs;
        } catch(SQLException ex) {
            throw new EJBException("Error in SELECT statement", ex);
        } finally {
            DatabaseUtil.closeConnection(conn, ps);
        }
    }

    public Integer getId() {
        return id;
    }

    public String getCaption() {
        return caption;
    }

    public void setCaption(String caption) {
        this.caption = caption;
        isEdited = true;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
        isEdited = true;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
        isEdited = true;
    }

    public Integer getThreadId() {
        return threadId;
    }

    public void setThreadId(Integer threadId) {
        this.threadId = threadId;
        isEdited = true;
    }

    public Date getPostDate() {
        return postDate;
    }

    public void setPostDate(Date postDate) {
        this.postDate = postDate;
        isEdited = true;
    }

    public String getStringRepresentation() {
        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getName());
        sb.append(": [id=");
        sb.append(id);
        sb.append(", caption=");
        sb.append(caption);
        sb.append(", text=");
        sb.append(text);
        sb.append(", userId=");
        sb.append(userId);
        sb.append(", threadId=");
        sb.append(threadId);
        sb.append(", postDate=[");
        sb.append(postDate.toString());
        sb.append("]]");
        return sb.toString();
    }

    public Element toXMLElement() {
        Element root = new Element("Message");
        XMLHelper.addElement(root, "id", id);
        XMLHelper.addElement(root, "caption", caption);
        XMLHelper.addElement(root, "text", text);
        XMLHelper.addElement(root, "userId", userId);
        XMLHelper.addElement(root, "threadId", threadId);
        XMLHelper.addElement(root, "postDate", postDate);
        return root;
    }

    public void loadFromXMLElement(Element data) {
        throw new UnsupportedOperationException();
    }
    
}
